package com.atguigu.tingshu.common.threadpool;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @Author：yyj
 * @Package：com.atguigu.tingshu.common.threadpool
 * @Project：tingshu_parent240829
 * @name：ThreadPoolConfiguration
 * @Date：2025/2/6 21:21
 * @Filename：ThreadPoolConfiguration
 */
@Configuration
@EnableConfigurationProperties(ThreadProperties.class)
public class ThreadPoolConfiguration {

    Logger logger = LoggerFactory.getLogger(ThreadPoolConfiguration.class);


    @Autowired
    private ThreadProperties threadProperties;


    @Value("${spring.application.name}")
    private String appName;

    @Value("${server.port}")
    private String port;

    /**
     * 自定义线程池对象
     * <p>
     * 自定义线程池对象的参数最少是5个 最多是7个
     * 5个：
     * param1: 核心线程数
     * param2: 最大线程数
     * param3: 空闲线程存活时间
     * param4: 时间单位
     * param5: 阻塞队列
     * 7个：
     * param1: 核心线程数
     * param2: 最大线程数
     * param3: 空闲线程存活时间
     * param4: 时间单位
     * param5: 阻塞队列
     * param6: 线程工厂
     * param7: 拒绝策略
     * <p>
     * <p>
     * <p>
     * 面试题：
     * 核心线程数、最大线程数、阻塞队列给多少
     * 核心线程数、最大线程数的设定要根据任务的类型设置。
     * 任务类型：
     * 1、cpu密集型任务：让cpu一直忙，从百万数据中找素数
     * 2、io密集型任务： 网络读取数据，从网络中发送数据、对磁盘数据的读写（rpc /mysql）对文件数据的读写
     * 3、混合型任务（cpu+io）
     * cpu密集型任务： 核心线程数：cpu核数+1
     * io密集型任务：  核心线程数：cpu核数*2===30
     * <p>
     * 压测：通过压测工具：分析任务属于io还是cpu型：压测工具：jmeter ApiPost
     * cpu核数获取： Runtime.getRuntime().availableProcessors();
     * <p>
     * <p>
     * 最终核心线程数设置多少：一定压测任务。（线程数一定比理论公式算出来高很多）
     * <p>
     * 最大线程数设定：
     * 1、一般并发比较低的公司 最大线程数=核心线程数
     * 2、并发比较高的公司：也得压测（观看接口的响应时间） 最大线程数=核心线程数*2
     * <p>
     * 阻塞队列给多少：（1、追求的接口响应速度是否快）如果想让任务返回的响应时间更短（队列大小要小一些） 反之就是大一些 压测得到。
     * (Nacos设定的阻塞队列大小1024*1024)
     * 粗的结论：我压测的结果：（核心是500 最大是1000） 队列大小（5000）
     * Tomcat 自定义线程池：核心线程数：10个  最大线程数（200）
     *
     * @return
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {


        // 自定义线程工程
        ThreadFactory threadFactory = new ThreadFactory() {
            AtomicInteger atomicInteger = new AtomicInteger(0);

            @Override
            public Thread newThread(@NotNull Runnable r) {
                Thread thread = new Thread(r);
//                thread.start();// 不用继续start. 线程池底层会获取自定义的线程工厂对象，然后调用newThread方法
                thread.setName(appName + "-" + port + "-" + atomicInteger.incrementAndGet());
                return thread;
            }
        };

        // 自定义拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                logger.error("提交任务：{}被自定义的拒绝策略收到", r);
                throw new RejectedExecutionException("Task " + r.toString() +
                        " rejected from " +
                        e.toString());
            }
        };
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(threadProperties.getCorePoolSize(),
                threadProperties.getMaximumPoolSize(),
                threadProperties.getTtl(),
                threadProperties.getUnit(),
                new LinkedBlockingQueue<Runnable>(threadProperties.getBlockQueueSize()),
                threadFactory,
                rejectedExecutionHandler);
        return threadPoolExecutor;

    }
}